home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gigarom 4
/
Mac Giga-ROM 4.0 - 1993.toast
/
FILES
/
EXT
/
A-E
/
basicblack1.0.cpt
/
Basic Black
/
Basic Black.c
next >
Wrap
C/C++ Source or Header
|
1993-03-27
|
13KB
|
425 lines
/**********************************************************
* Basic Black © 1993 by Mason L. Bliss
*
* This is a minimal screen saver. All it does (though it
* can be easily extended) is black out the screen after a
* specified time. It lets background (and foreground, for
* that matter) tasks run at full speed, as it doesn't waste
* any time on whizbang graphics. (Hence the name...)
*
* The trap patching code is taken from a neat little program
* Mike Scanlin wrote for the August '92 MacTutor.
*
* Basic Black's screen-blanking routine is based on a routine
* by Christopher Tate.
*
* It also makes use of CShowInit, by Ken McLeod, to put
* up its icon at startup time.
**********************************************************/
#include "Traps.h"
#define ON 1
#define OFF 0
#define SLEEPTICKS 7200 /* 7200 ticks = 2 minutes */
#define INSTANTSLEEPTICKS 45 /* 1 minute = 3600 ticks */
/**********************************************************
* typedefs
**********************************************************/
typedef pascal short (*WNEProcPtr) (short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn);
typedef pascal short (*GNEProcPtr) (short eventMask, EventRecord *theEvent);
typedef pascal short (*SEProcPtr) (EventRecord *theEvent);
typedef pascal short (*STProcPtr) (void);
typedef struct {
char privates[76];
long randSeed;
BitMap screenBits;
Cursor arrow;
Pattern dkGray;
Pattern ltGray;
Pattern black;
Pattern white;
GrafPtr thePort;
long qdend;
} QDGlobals;
typedef struct PatchGlobals {
WNEProcPtr pgOldWNE;
GNEProcPtr pgOldGNE;
SEProcPtr pgOldSE;
STProcPtr pgOldST;
short pgSleepState,
pgGonnaFallAsleep,
pgOldMBarHeight;
long pgLastAction;
Point pgLastMouse;
Rect pgSleepRect,
pgWakeRect;
GrafPort pgMyPort;
GrafPtr pgOldPort;
RgnHandle pgOldGrayRgn,
pgNullRgn;
WindowPtr pgFrontWin;
} PatchGlobals, *PatchGlobalsPtr;
/**********************************************************
* prototypes
**********************************************************/
void main(void);
void StartPatchCode(void);
pascal short MyWaitNextEvent(short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn);
pascal short MyGetNextEvent(short eventMask, EventRecord *theEvent);
pascal short MySystemEvent(EventRecord *theEvent);
void MySystemTask(void);
void FallAsleep(void);
void WakeUp(void);
void EndPatchCode(void);
/**********************************************************
* main:
* Gets memory in the system heap, and installs the WNE, GNE,
* and SE patches (as well as allocating and initializing
* the patch globals). This is the only routine that gets
* executed at startup time (by the INIT mechanism).
*
* The block of memory that main allocates will look like
* this when main has finished:
*
* +--------------------+
* | PatchGlobals |
* +--------------------+
* | StartPatchCode() |
* WNE trap addr -> +--------------------+
* | MyWaitNextEvent() |
* GNE trap addr -> +--------------------+
* | MyGetNextEvent() |
* SE trap addr -> +--------------------+
* | MySystemEvent() |
* ST trap addr -> +--------------------+
* | MySystemTask() |
* +--------------------+
* | CheckKeyCase() |
* +--------------------+
* | EndPatchCode() |
* +--------------------+
*
**********************************************************/
void main()
{
Ptr patchPtr;
PatchGlobalsPtr pgPtr;
long codeSize, offset, oldA5;
QDGlobals qd;
GrafPort gp;
/* try and get some memory in the system heap for code and globals */
codeSize = (long) EndPatchCode - (long) StartPatchCode;
patchPtr = NewPtrSys(codeSize + sizeof(PatchGlobals));
if (!patchPtr)
return; /* out of memory -- abort patching */
// initialize the patch globals at the beginning of the block
pgPtr = (PatchGlobalsPtr) patchPtr;
pgPtr->pgOldWNE = (WNEProcPtr) GetTrapAddress(_WaitNextEvent);
pgPtr->pgOldGNE = (GNEProcPtr) GetTrapAddress(_GetNextEvent);
pgPtr->pgOldSE = (SEProcPtr) GetTrapAddress(_SystemEvent);
pgPtr->pgOldST = (STProcPtr) GetTrapAddress(_SystemTask);
pgPtr->pgSleepState = OFF;
pgPtr->pgGonnaFallAsleep = OFF;
pgPtr->pgLastAction = Ticks;
pgPtr->pgNullRgn = 0L;
// This next bit of stuff fakes out some QuickDraw globals to get the
// correct sleep and wake rectangles.
oldA5 = SetA5((long) &qd.qdend); // Tell A5 to point to our 'fake' QD Globals
InitGraf(&qd.thePort); // Initialize our QD Globals
OpenPort((GrafPtr) &gp);
(pgPtr->pgSleepRect).left = (gp.portRect).right - 5; // Set sleep rect
(pgPtr->pgSleepRect).right = (gp.portRect).right + 1;
(pgPtr->pgSleepRect).top = (gp.portRect).top - 1;
(pgPtr->pgSleepRect).bottom = (gp.portRect).top + 5;
(pgPtr->pgWakeRect).left = (gp.portRect).right - 5; // Set wake rect
(pgPtr->pgWakeRect).right = (gp.portRect).right + 1;
(pgPtr->pgWakeRect).top = (gp.portRect).bottom - 5;
(pgPtr->pgWakeRect).bottom = (gp.portRect).bottom + 1;
ClosePort((GrafPtr) &gp);
oldA5 = SetA5(oldA5); // Restore A5 to its previous value
GetMouse(&(pgPtr->pgLastMouse));
LocalToGlobal(&(pgPtr->pgLastMouse));
/* move the code into place after the globals */
BlockMove(StartPatchCode, patchPtr + sizeof(PatchGlobals), codeSize);
/* set the patches */
patchPtr += sizeof(PatchGlobals);
offset = (long) MyWaitNextEvent - (long) StartPatchCode;
SetTrapAddress((long) patchPtr + offset, _WaitNextEvent);
offset = (long) MyGetNextEvent - (long) StartPatchCode;
SetTrapAddress((long) patchPtr + offset, _GetNextEvent);
offset = (long) MySystemEvent - (long) StartPatchCode;
SetTrapAddress((long) patchPtr + offset, _SystemEvent);
offset = (long) MySystemTask - (long) StartPatchCode;
SetTrapAddress((long) patchPtr + offset, _SystemTask);
}
/**********************************************************
* StartPatchCode:
* Dummy proc to mark the beginning of the code for the
* patches. Make sure all of your patch code is between
* here and EndPatchCode.
**********************************************************/
void StartPatchCode()
{
}
/**********************************************************
* MyWaitNextEvent:
* Tail patch on WaitNextEvent.
*
* The reason this returns a short instead of a Boolean is
* because we need to make sure the low byte of the top word
* on the stack is zero because some programs do a Tst.W
* (SP)+ when this returns instead of Tst.B (SP)+ like they
* should (which is technically their bug but, we might as
* well work around it since it's not hard).
*
* If you want to eat the event and not pass it on to the
* caller then set returnValue to zero.
**********************************************************/
pascal short MyWaitNextEvent(short eventMask, EventRecord *theEvent, long sleep, RgnHandle mouseRgn)
{
PatchGlobalsPtr pgPtr;
short returnValue;
register short foo;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
/* call original GNE first */
returnValue = (*pgPtr->pgOldWNE) (eventMask, theEvent, sleep, mouseRgn);
if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
pgPtr->pgLastAction = Ticks; /* Update last time counter */
pgPtr->pgGonnaFallAsleep = OFF;
if (pgPtr->pgSleepState)
WakeUp();
}
/* return to original caller */
return (returnValue);
}
/**********************************************************
* MyGetNextEvent:
* Tail patch on GetNextEvent.
*
* The reason this returns a short instead of a Boolean is
* because we need to make sure the low byte of the top word
* on the stack is zero because some programs do a Tst.W
* (SP)+ when this returns instead of Tst.B (SP)+ like they
* should (which is technically their bug but, we might as
* well work around it since it's not hard).
*
* If you want to eat the event and not pass it on to the
* caller then set returnValue to zero.
**********************************************************/
pascal short MyGetNextEvent(short eventMask, EventRecord *theEvent)
{
PatchGlobalsPtr pgPtr;
short returnValue;
register short foo;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
/* call original GNE first */
returnValue = (*pgPtr->pgOldGNE) (eventMask, theEvent);
if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
pgPtr->pgLastAction = Ticks; /* Update last time counter */
pgPtr->pgGonnaFallAsleep = OFF;
if (pgPtr->pgSleepState)
WakeUp();
}
/* return to original caller */
return (returnValue);
}
/**********************************************************
* MySystemEvent:
* Tail patch on SystemEvent.
*
* The reason this returns a short instead of a Boolean is
* because we need to make sure the low byte of the top word
* on the stack is zero because some programs do a Tst.W
* (SP)+ when this returns instead of Tst.B (SP)+ like they
* should (which is technically their bug but, we might as
* well work around it since it's not hard).
*
* We need this patch as well as the one on GetNextEvent
* because of desk accessories. If you don't patch
* SystemEvent then the patch will not apply to events that
* are sent to DAs.
*
* If you want to eat the event and not pass it on to the
* caller then set returnValue to zero.
**********************************************************/
pascal short MySystemEvent(EventRecord *theEvent)
{
PatchGlobalsPtr pgPtr;
short returnValue;
register short foo;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
/* call original SE first */
returnValue = (*pgPtr->pgOldSE) (theEvent);
if ((foo = theEvent->what) >= 1 && foo <= 5 || foo == 7) {
pgPtr->pgLastAction = Ticks; /* Update last time counter */
pgPtr->pgGonnaFallAsleep = OFF;
if (pgPtr->pgSleepState)
WakeUp();
}
/* return to original caller */
return (returnValue);
}
/**********************************************************
* MySystemTask:
* Tail patch on SystemTask.
*
* This is where most of the stuff's done.
**********************************************************/
void MySystemTask(void)
{
PatchGlobalsPtr pgPtr;
Point mousePt;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
/* call original ST first */
(*pgPtr->pgOldST) ();
GetMouse(&mousePt);
LocalToGlobal(&mousePt);
if (!EqualPt(mousePt, pgPtr->pgLastMouse)) { /* Mouse moved */
pgPtr->pgLastMouse = mousePt;
pgPtr->pgLastAction = Ticks;
pgPtr->pgGonnaFallAsleep = OFF;
if (pgPtr->pgSleepState)
WakeUp();
}
if (!(pgPtr->pgGonnaFallAsleep) && PtInRect(mousePt, &pgPtr->pgSleepRect)) {
pgPtr->pgGonnaFallAsleep = ON;
pgPtr->pgLastAction -= (SLEEPTICKS - INSTANTSLEEPTICKS);
}
if (PtInRect(mousePt, &pgPtr->pgWakeRect))
pgPtr->pgLastAction = Ticks;
if (((Ticks - (pgPtr->pgLastAction)) > SLEEPTICKS) && !(pgPtr->pgSleepState))
FallAsleep();
}
/**********************************************************
* FallAsleep:
*
* This is where we black out the screen.
**********************************************************/
void FallAsleep(void)
{
PatchGlobalsPtr pgPtr;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
/* Kill off the menu bar and cursor, and get ready for bed */
pgPtr->pgSleepState = ON;
pgPtr->pgOldMBarHeight = MBarHeight;
MBarHeight = 0;
HideCursor();
/* Here's where it happens */
GetPort(&(pgPtr->pgOldPort)); /* Get the old port */
OpenPort(&(pgPtr->pgMyPort));
pgPtr->pgOldGrayRgn = GrayRgn;
GrayRgn = pgPtr->pgNullRgn;
PaintRect(&(pgPtr->pgMyPort.portRect));
/* No man may draw here. */
CalcVisBehind((WindowPeek) FrontWindow(), pgPtr->pgOldGrayRgn);
SetPort(pgPtr->pgOldPort); /* Set up the old port */
}
/**********************************************************
* WakeUp:
*
* This is where we force a redraw and give things access
* to the screen again.
**********************************************************/
void WakeUp(void)
{
PatchGlobalsPtr pgPtr;
/* find our globals */
pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode - sizeof(PatchGlobals));
pgPtr->pgSleepState = OFF;
pgPtr->pgGonnaFallAsleep = OFF;
pgPtr->pgLastAction = Ticks;
MBarHeight = pgPtr->pgOldMBarHeight;
/* This next block is Chris' code */
GetPort(&(pgPtr->pgOldPort));
SetPort(&(pgPtr->pgMyPort));
GrayRgn = pgPtr->pgOldGrayRgn;
pgPtr->pgFrontWin = FrontWindow();
PaintBehind((WindowPeek) pgPtr->pgFrontWin, GrayRgn);
CalcVisBehind((WindowPeek) pgPtr->pgFrontWin, GrayRgn); /* force redraw */
DrawMenuBar();
ShowCursor();
ClosePort(&(pgPtr->pgMyPort));
SetPort(pgPtr->pgOldPort);
}
/**********************************************************
* EndPatchCode:
* Dummy proc to mark the end of the code for the patches.
* Make sure all of your patch code is between here and
* StartPatchCode.
**********************************************************/
void EndPatchCode()
{
}